package cn.com.ejiakanghu.service;

import cn.com.ejiakanghu.dto.FeightFeeResult;
import cn.com.ejiakanghu.dto.LeaseRefundData;
import cn.com.ejiakanghu.dto.ShunfengFeeResult;
import cn.com.ejiakanghu.dto.TempSubOrderParamDelivery;
import cn.com.ejiakanghu.tools.OrderFeeExtNameEnum;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.ArrayUtils;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GeodeticCurve;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.linlinjava.litemall.core.util.InventoryUtil;
import org.linlinjava.litemall.db.dao.AgedmallChargeTemplateLeasePeriodMapper;
import org.linlinjava.litemall.db.dao.AgedmallCloudHouseMapper;
import org.linlinjava.litemall.db.dao.AgedmallHospitalSendSelfLocationMapper;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.jsonfield.*;
import org.linlinjava.litemall.db.service.*;
import org.linlinjava.litemall.db.service.oder_manage.AgedMallOrderDbService;
import org.linlinjava.litemall.db.service.oder_manage.AgedmallOrderLogisticService;
import org.linlinjava.litemall.db.util.AgedmallShipDictConstant;
import org.linlinjava.litemall.db.util.GoodsConstant;
import org.linlinjava.litemall.db.util.OrderGoodsConstant;
import org.linlinjava.litemall.db.vo.app.FreightGoodsDto;
import org.linlinjava.litemall.db.vo.app.StoreGoodsVo;
import org.linlinjava.litemall.db.vo.shop.HospitalSendTimePeriodDto;
import org.linlinjava.litemall.db.vo.store.CloudExpressModelForm;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 订单计算服务
 */
@Service
public class OrderCalcService {
    private Logger logger = LoggerFactory.getLogger(OrderCalcService.class);

    @Autowired
    private AgedmallStoreGoodsService agedmallStoreGoodsService;
    @Autowired
    private AgedmallChargeTemplateService agedmallChargeTemplateService;
    @Autowired
    private AgedmallFreightTemplateService agedmallFreightTemplateService;
    @Autowired
    private AgedmallHospitalSendService agedmallHospitalSendService;
    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private AgedmallLeaseGoodsReturnRecordService agedmallLeaseGoodsReturnRecordService;
    @Autowired
    private LitemallOrderGoodsService litemallOrderGoodsService;
    @Autowired
    private AgedmallOrderLogisticService agedmallOrderLogisticService;
    @Autowired
    private AgedmallOnlinesService agedmallOnlinesService;
    @Autowired
    private AgedMallOrderDbService agedMallOrderDbService;
    @Resource
    private AgedmallCloudHouseMapper agedmallCloudHouseMapper;
    @Resource
    private AgedmallHospitalSendSelfLocationMapper agedmallHospitalSendSelfLocationMapper;
    @Resource
    private AgedmallChargeTemplateLeasePeriodMapper agedmallChargeTemplateLeasePeriodMapper;

    /**
     * 计算租赁时长 天数
     *
     * @param shipArriveTime
     * @param endTIme
     * @return
     */
    public int calLeaseDays(LocalDateTime shipArriveTime, LocalDateTime endTIme) {
        if (shipArriveTime == null || endTIme == null) {
            return 0;
        }
        Long days = endTIme.toLocalDate().toEpochDay() - shipArriveTime.toLocalDate().toEpochDay();
        //租赁天数至少一天,不足一天按一天计算
        int leaseDays = days <= 0 ? 1 : days.intValue();
        return leaseDays;
    }

    /**
     * 根据门店商品id 和 天数 获取租金
     *
     * @param storeGoodsId
     * @param day
     * @param ruleId  收费模板起租期id
     * @return
     */
    public BigDecimal ladderCountRent(int storeGoodsId, Long day,Long ruleId) {
        // 门店商品信息
        StoreGoodsVo info = agedmallStoreGoodsService.getStoreGoodsById(storeGoodsId);
        if (info == null) {
            logger.error("计算租金 门店信息null:{},{}", storeGoodsId, day);
            return BigDecimal.ZERO;
        }
        // 门店商品模板
        AgedmallChargeTemplate agedmallChargeTemplate = agedmallChargeTemplateService.findById(info.getLeaseChargeTemolateId());
        AgedmallChargeTemplateLeasePeriod leasePeriod=agedmallChargeTemplateLeasePeriodMapper.selectByPrimaryKey(ruleId);
        if (null == agedmallChargeTemplate||null == leasePeriod) {
            logger.error("计算租金 商品模板null:{},{},{}", storeGoodsId, day,ruleId);
            return BigDecimal.ZERO;
        }

        //商品租赁信息类
        AgedmallLeaseLadderRuleConfRuleInfo ruleInfo = new AgedmallLeaseLadderRuleConfRuleInfo();
        ruleInfo.setMinDays(leasePeriod.getBaseDay());
        if (agedmallChargeTemplate.getTopPriceType() == 0) {
            ruleInfo.setMaxFee(info.getLeaseDeposit());
        } else {
            ruleInfo.setMaxFee(agedmallChargeTemplate.getTopPrice());
        }
        List<LeaseLadderChargeRuleItemInfo> afterRules = JSONObject.parseArray(leasePeriod.getLadderPrice(), LeaseLadderChargeRuleItemInfo.class);
        LeaseLadderChargeRuleItemInfo first = new LeaseLadderChargeRuleItemInfo();
        first.setBegin(0L);
        first.setEnd(leasePeriod.getBaseDay().longValue());
        first.setPrice(leasePeriod.getBasePrice());
        List<LeaseLadderChargeRuleItemInfo> rules = new ArrayList<>();
        rules.add(first);
        rules.addAll(afterRules);
        ruleInfo.setRules(rules);

        day = day < ruleInfo.getMinDays() ? ruleInfo.getMinDays() : day;

        BigDecimal totalPrice = BigDecimal.ZERO;
        for (LeaseLadderChargeRuleItemInfo itemInfo : ruleInfo.getRules()) {
            if (day < itemInfo.getBegin()) {
                continue;
            }
            long beginDay = itemInfo.getBegin() == 0 ? 1 : itemInfo.getBegin();
            long endDay = day >= itemInfo.getEnd() ? itemInfo.getEnd() : day;
            BigDecimal price = itemInfo.getPrice().multiply(new BigDecimal(endDay - beginDay + 1));
            if (null != itemInfo.getMaxFee() && itemInfo.getMaxFee().compareTo(BigDecimal.ZERO) > 0) {
                totalPrice = totalPrice.add(price.compareTo(itemInfo.getMaxFee()) > 0 ? itemInfo.getMaxFee() : price);
            } else {
                totalPrice = totalPrice.add(price);
            }
        }

        totalPrice = totalPrice.compareTo(ruleInfo.getMaxFee()) > 0 ? ruleInfo.getMaxFee() : totalPrice;
        return totalPrice;
    }

    /**
     * 计算运费
     *
     * @param storeGoodsVos
     * @param litemallAddress
     * @param store
     * @return
     */
    public FeightFeeResult calFeightFee(List<StoreGoodsVo> storeGoodsVos, LitemallAddress litemallAddress, AgedmallStore store) {
        List<FreightGoodsDto> freightGoodsDtoList = new ArrayList<>();
        BigDecimal normalPrice = BigDecimal.ZERO;
        boolean isContainCloudStore = false;
        Integer isOutRange = null;
        for (StoreGoodsVo goodsVo : storeGoodsVos) {
            FreightGoodsDto freightGoodsDto = new FreightGoodsDto();
            freightGoodsDto.setId(goodsVo.getStoreGoodsId());
            freightGoodsDto.setName(goodsVo.getName());
            freightGoodsDto.setImage(goodsVo.getPicUrl());
            freightGoodsDto.setStockInfo("同城配送(" + store.getStoreName() + ")");
            //是否先付后付，0先付，1后付,后付前端不做费用增加
            // 免运费
            if (1 == goodsVo.getFreight()) {
                continue;
                // 满足条件免运费
            } else if (2 == goodsVo.getFreight()) {
                BigDecimal goodsPrice = null;
                if (GoodsConstant.GOODS_TYPE_SALE.equals(goodsVo.getGoodsType())) {
                    goodsPrice = goodsVo.getSaleRetailPrice().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                } else {
                    goodsPrice = goodsVo.getLeaseDeposit().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                }
                if (goodsPrice.compareTo(goodsVo.getFreightCondition()) >= 0) {
                    continue;
                } else {
                    BigDecimal tempPrice = null;
                    // 是否云仓
                    if (InventoryUtil.STOCK_CLOUD.equals(goodsVo.getStockType())) {
                        isContainCloudStore = true;
                        tempPrice = getCloudFeight(goodsVo, litemallAddress.getProvinceId(),goodsVo.getCloudStockId(),false);
                        if (goodsVo.getCloudStockId() != null) {
                            agedmallCloudHouseMapper.selectByPrimaryKey(goodsVo.getCloudStockId());
                            freightGoodsDto.setStockInfo("云仓配送(" + store.getStoreName() + ")");
                        }
                    } else {
                        tempPrice = getFeight(goodsVo, store, litemallAddress.getLng(), litemallAddress.getLat(),false);
                    }
                    if (tempPrice.compareTo(BigDecimal.ZERO) >= 0) {
                        normalPrice = normalPrice.add(tempPrice);
                    } else {
                        isOutRange = 1;
                    }
                }
                // 不免运费
            } else {
                BigDecimal tempPrice = null;
                // 是否云仓
                if (InventoryUtil.STOCK_CLOUD.equals(goodsVo.getStockType())) {
                    isContainCloudStore = true;
                    tempPrice = getCloudFeight(goodsVo, litemallAddress.getProvinceId(),goodsVo.getCloudStockId(),false);
                    if (goodsVo.getCloudStockId() != null) {
                        agedmallCloudHouseMapper.selectByPrimaryKey(goodsVo.getCloudStockId());
                        freightGoodsDto.setStockInfo("云仓配送(" + store.getStoreName() + ")");
                    }
                } else {
                    tempPrice = getFeight(goodsVo, store, litemallAddress.getLng(), litemallAddress.getLat(),false);
                }
                if (tempPrice.compareTo(BigDecimal.ZERO) >= 0) {
                    normalPrice = normalPrice.add(tempPrice);
                } else {
                    isOutRange = 1;
                }
            }
            freightGoodsDto.setPrice(normalPrice);
            freightGoodsDtoList.add(freightGoodsDto);
        }
        FeightFeeResult result = new FeightFeeResult();
        result.setNormalFee(normalPrice);
        result.setContainIsCloudStore(isContainCloudStore);
        result.setOutRangeRst(isOutRange);
        result.setFreightGoodsDtoList(freightGoodsDtoList);
        return result;
    }


    /**
     * 获取运费计算详情  HTML文本，前端使用
     *
     * @param pickUp 是否是取回
     * @return
     */
    public String getDeliveryMessageDesc(StoreGoodsVo goodsVo, Integer provinceId, Integer cloudStockId, boolean pickUp,
                                         AgedmallStore store, BigDecimal lng, BigDecimal lat) {
        StringBuilder stringBuilder = new StringBuilder();
        //统一运费
        if (goodsVo.getLogisticsType() == (byte) 0) {
            //云仓
            if (cloudStockId != null) {
                List<CloudExpressModelForm> cloudExpressModelFormList = JSONArray.parseArray(goodsVo.getCloudJson(), CloudExpressModelForm.class);
                CloudExpressModelForm cloudModel = cloudExpressModelFormList.stream().filter(express -> express.getId().equals(cloudStockId)).findFirst().get();
                stringBuilder.append("<div>统一运费￥");
                stringBuilder.append(cloudModel.getDeliveryCost());
                stringBuilder.append("/件</div>");
            }
            //正常配送
            else if (!pickUp) {
                if (goodsVo.getSameCitySendType() == 0) {
                    stringBuilder.append("<div>统一运费￥");
                    stringBuilder.append(goodsVo.getExpressCost());
                    stringBuilder.append("/件</div>");
                } else {
                    stringBuilder.append("<div>统一运费￥");
                    stringBuilder.append(goodsVo.getSameCityCost());
                    stringBuilder.append("/件</div>");
                }
            }
            //同城 取回
            else {
                stringBuilder.append("<div>统一运费￥");
                stringBuilder.append(goodsVo.getPickUpCost());
                stringBuilder.append("/件</div>");
            }
        }
        //运费模板
        else {
            if (cloudStockId != null) {
                List<CloudExpressModelForm> cloudExpressModelFormList = JSONArray.parseArray(goodsVo.getCloudJson(), CloudExpressModelForm.class);
                CloudExpressModelForm cloudModel = cloudExpressModelFormList.stream().filter(express -> express.getId().equals(cloudStockId)).findFirst().get();
                String cloudHtml = getCloudHtmlDesc(goodsVo, cloudModel.getModelDeliveryId().longValue(), provinceId);
                stringBuilder.append(cloudHtml);
            } else {
                Long templateId = null;
                if(pickUp){
                    templateId=goodsVo.getPickUp().longValue();
                }
                else{
                    Integer sameCitySendType = goodsVo.getSameCitySendType();
                    if (sameCitySendType != null && sameCitySendType == 0) {
                        Integer express = goodsVo.getExpress();
                        templateId = express != null ? express.longValue() : null;
                    } else {
                        Integer sameCity = goodsVo.getSameCity();
                        templateId = sameCity != null ? sameCity.longValue() : null;
                    }
                }

                String storeHtml = getFeightHtmlDesc(goodsVo, store, templateId, lng, lat);
                stringBuilder.append(storeHtml);
            }
        }
        return stringBuilder.toString();
    }


    /**
     * 获取快递html信息
     *
     * @param goodsVo
     * @param provinceId
     * @return
     */
    public String getCloudHtmlDesc(StoreGoodsVo goodsVo, Long templateId, Integer provinceId) {

        StringBuilder stringBuilder = new StringBuilder();

        AgedmallFreightTemplate freightTemplate = agedmallFreightTemplateService.findById(templateId);
        List<ExpressFreightTemplate> expressFreightTemplates = JSONObject.parseArray(freightTemplate.getExpressTemplate(), ExpressFreightTemplate.class);

        for (ExpressFreightTemplate expressFreightTemplate : expressFreightTemplates) {
            String[] regionArr = expressFreightTemplate.getRegion().split(",");
            if (ArrayUtils.contains(regionArr, provinceId + "")) {
                BigDecimal number = BigDecimal.ZERO;
                //获取运费
                BigDecimal cloudFeight = getCloudFeight(goodsVo, provinceId,goodsVo.getCloudStockId(),false);

                //按件
                if (0 == freightTemplate.getPayType()) {
                    number = BigDecimal.valueOf(goodsVo.getStock());
                    // 按重量
                } else {
                    number = goodsVo.getWeight().divide(BigDecimal.valueOf(1000));
                }
                // 按件
                if (0 == freightTemplate.getPayType()) {
                    stringBuilder.append("<div>");
                    stringBuilder.append("续件运费：").append(cloudFeight);
                    stringBuilder.append("</div>");

                    stringBuilder.append("<div>");
                    stringBuilder.append(expressFreightTemplate.getTheFirstPiece()).append("件内收费").append(expressFreightTemplate.getPiece()).append("元，");
                    stringBuilder.append("</div>");

                    stringBuilder.append("<div>");
                    stringBuilder.append("总共").append(number).append("件，");
                    stringBuilder.append("超出部分每").append(expressFreightTemplate.getAhead()).append("件收费").append(expressFreightTemplate.getCharge()).append("元");
                    stringBuilder.append("</div>");
                    // 按重量
                } else {
                    stringBuilder.append("<div>");
                    stringBuilder.append("续重运费").append(cloudFeight);
                    stringBuilder.append("</div>");

                    stringBuilder.append("<div>");
                    stringBuilder.append(expressFreightTemplate.getTheFirstPiece()).append("KG内收费").append(expressFreightTemplate.getPiece()).append("元，");
                    stringBuilder.append("</div>");

                    stringBuilder.append("<div>");
                    stringBuilder.append("总共").append(number).append("KG，");
                    stringBuilder.append("超出部分每").append(expressFreightTemplate.getAhead()).append("KG收费").append(expressFreightTemplate.getCharge()).append("元");
                    stringBuilder.append("</div>");
                }
                break;
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 获取同城运费html信息
     */
    public String getFeightHtmlDesc(StoreGoodsVo goodsVo, AgedmallStore store, Long templateId, BigDecimal lng, BigDecimal lat) {
        StringBuilder stringBuilder = new StringBuilder();

        AgedmallFreightTemplate freightTemplate = templateId != null ? agedmallFreightTemplateService.findById(templateId) : null;
        if(freightTemplate == null) {
            logger.error("运费模板为空 {}", goodsVo.getId());
            return "";
        }
        GlobalCoordinates source = new GlobalCoordinates(lat.doubleValue(), lng.doubleValue());
        GlobalCoordinates target = new GlobalCoordinates(store.getLat().doubleValue(), store.getLng().doubleValue());
        GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target);
        double distance = geoCurve.getEllipsoidalDistance();
        //总距离
        BigDecimal meter = new BigDecimal(distance / 1000);
        //获取运费
        BigDecimal feight = getFeight(goodsVo, store, lng, lat,false);

        BigDecimal number = BigDecimal.ZERO;


        if (1 == freightTemplate.getPayType()) {
            stringBuilder.append("<div>");
            stringBuilder.append("公里运费").append(feight);
            stringBuilder.append("</div>");

            stringBuilder.append("<div>");
            stringBuilder.append("配送范围").append(freightTemplate.getDeliveryRange()).append("公里，收费").append(freightTemplate.getFixedPay()).append("元");
            stringBuilder.append("</div>");
        } else {
            // 未超出配送范围

            stringBuilder.append("<div>");
            stringBuilder.append("公里运费").append(feight);
            stringBuilder.append("</div>");


            if (meter.compareTo(freightTemplate.getSameCityFirstUnit()) < 1) {
                stringBuilder.append("<div>");
                stringBuilder.append("配送范围").append(freightTemplate.getSameCityFirstUnit()).append("公里，收费").append(freightTemplate.getSameCityFirstUnitPay()).append("元");
                stringBuilder.append("</div>");
            } else {
                // 超出距离倍数

                stringBuilder.append("<div>");
                stringBuilder.append("起步：").append(freightTemplate.getSameCityFirstUnit()).append("公里，收费").append(freightTemplate.getSameCityFirstUnitPay()).append("元");
                stringBuilder.append("</div>");

                stringBuilder.append("<div>");
                stringBuilder.append("总共：").append(meter.setScale(4,BigDecimal.ROUND_DOWN)).append("公里，")
                        .append("超出部分每").append(freightTemplate.getSameCityAfterUnit()).append("公里收费").append(freightTemplate.getSameCityAfterUnitPay()).append("元");
                stringBuilder.append("</div>");
                int rate = (meter.subtract(freightTemplate.getSameCityFirstUnit())).divide(freightTemplate.getSameCityAfterUnit()).setScale(0, BigDecimal.ROUND_CEILING).intValue();
                BigDecimal afterPrice = freightTemplate.getSameCityAfterUnitPay().multiply(BigDecimal.valueOf(rate));
                logger.debug("按距离配送,配送范围{}公里，固定收费{}，超出部分每{}公里收费{}，共收费{}", freightTemplate.getSameCityFirstUnit(),
                        freightTemplate.getSameCityFirstUnitPay(), freightTemplate.getSameCityAfterUnit(), freightTemplate.getSameCityAfterUnitPay(), afterPrice);
            }

        }


        if (freightTemplate.getAdditionalPayType()==null||0 == freightTemplate.getAdditionalPayType()) {

            // 超重计算
            BigDecimal actualWeight = goodsVo.getWeight().divide(BigDecimal.valueOf(1000));
            BigDecimal tempWeight = freightTemplate.getWeight();
            BigDecimal tempAfterUnit = freightTemplate.getWeightAfterUnit();
            if (tempWeight.compareTo(BigDecimal.ZERO) > 0 && tempAfterUnit.compareTo(BigDecimal.ZERO) > 0 && actualWeight.compareTo(tempWeight) > 0) {
                int overWeight = (actualWeight.subtract(freightTemplate.getWeight()).divide(tempAfterUnit)).setScale(0, BigDecimal.ROUND_CEILING).intValue();
                BigDecimal overPrice = freightTemplate.getWeightAfterUnitPay().multiply(BigDecimal.valueOf(overWeight));
                logger.debug("{}公斤内不收费，超出部分每{}公斤收费{}，当前{}公斤，共收费{}}", freightTemplate.getWeight(), freightTemplate.getWeightAfterUnit(),
                        freightTemplate.getWeightAfterUnitPay(), actualWeight, overPrice);
                stringBuilder.append("<div>");
                stringBuilder.append("总共").append(actualWeight).append("KG，");
                stringBuilder.append("超出部分每").append(freightTemplate.getWeightAfterUnit()).append("KG收费").append(freightTemplate.getWeightAfterUnitPay()).append("元");
                stringBuilder.append("</div>");
            }
        } else {
            number = BigDecimal.valueOf(goodsVo.getStock());
            if (freightTemplate.getWeight().compareTo(number) > 0) {
                //超出倍数
//                int beyondSize=freightTemplate.getWeight().subtract(number).divide(freightTemplate.getWeightAfterUnit()).setScale(0,BigDecimal.ROUND_UP).intValue();
//                BigDecimal beyondPrice=freightTemplate.getWeightAfterUnitPay().multiply(BigDecimal.valueOf(beyondSize));
                stringBuilder.append("<div>");
                stringBuilder.append("总共").append(number).append("件，");
                stringBuilder.append("超出部分每").append(freightTemplate.getWeightAfterUnit()).append("件收费").append(freightTemplate.getWeightAfterUnitPay()).append("元");
                stringBuilder.append("</div>");
            }

        }

        return stringBuilder.toString();
    }


    /**
     * 计算运费 增加配送费
     * 普通配送
     * <p>
     * 普通配送 = 子订单金额 + 普通配送费
     * 加急配送 = 子订单金额 + 普通配送费 + 加急感谢费
     * 预约配送 = 子订单金额 + 普通配送费 + 预约费
     * 自提配送 = 子订单金额 + 自提服务费
     * <p>
     * 医院专送
     * <p>
     * 今日小时达 = 子订单金额 + 普通配送费 + 加急费
     * 预约小时达 = 子订单金额 + 普通配送费 + 预约费
     * 今日到店自提 = 子订单金额 + 自提服务费
     * 预约到店自提 = 子订单金额 + 预约费
     * 预约到院自提 = 子订单金额 + 预约费
     *
     * @param storeGoodsVos
     * @param litemallAddress
     * @param store
     * @param delivery
     * @return
     */
    public FeightFeeResult calFeightFee(List<StoreGoodsVo> storeGoodsVos, LitemallAddress litemallAddress, AgedmallStore store, TempSubOrderParamDelivery delivery) {
        FeightFeeResult feightFeeResult = calFeightFee(storeGoodsVos, litemallAddress, store);
        BigDecimal normalPrice = feightFeeResult.getNormalFee();
        //运费配送费用
        BigDecimal deliveryPrice = BigDecimal.ZERO;
        //配送方式 加急，自提，快递
        String deliverySn = null;
        //配送选择相关属性信息
        String deliverChoose = null;
        //门店的id
        Integer extractShop = null;
        //是否选择了医院
        Integer isHospital = null;
        //选择的医院id
        Integer hospitalId = null;
        //选择的医院名称
        String hospitalName = null;
        if (null != delivery) {
            deliverySn = delivery.getType();
            if (AgedmallShipDictConstant.SHIP_SN_NORMAL.equals(delivery.getType())) {
                //没有特殊配送要求
                deliveryPrice = normalPrice;
            } else if (AgedmallShipDictConstant.SHIP_SN_URGENT.equals(delivery.getType())) {
                //用户选择的加急配送信息
                TempSubOrderParamDeliveryUrgent urgent = delivery.getUrgent();
                if (null != urgent) {
                    StoreGoodsVo storeGoods = storeGoodsVos.get(0);
                    AgedmallFreightTemplate freightTemplate = agedmallFreightTemplateService.findById(storeGoods.getSameCity().longValue());
                    urgent.setEarlyUrgentPay(freightTemplate.getEarlyUrgentPay());
                    urgent.setLastUrgentPay(freightTemplate.getLastUrgentPay());
                    deliverChoose = JSONObject.toJSONString(urgent);
                    deliveryPrice = normalPrice.add(urgent.getPrice());
                }
            } else if (AgedmallShipDictConstant.SHIP_SN_SELF.equals(delivery.getType())) {
                //用户选择的自提配送信息
                TempSubOrderParamDeliverySelf self = delivery.getSelf();
                if (null != self) {
                    self.setPrice(BigDecimal.ZERO);
                    deliverChoose = JSONObject.toJSONString(self);
                    extractShop = self.getShopId();
                    deliveryPrice = self.getPrice();
                }
            } else if (AgedmallShipDictConstant.SHIP_SN_SUBSCRIBE.equals(delivery.getType())) {
                //用户选择的预约配送信息
                StoreGoodsVo storeGoods = storeGoodsVos.get(0);
                AgedmallFreightTemplate freightTemplate = agedmallFreightTemplateService.findById(storeGoods.getSameCity().longValue());
                TempSubOrderParamDeliverySubscribe subscribe = delivery.getSubscribe();
                if (null != subscribe) {
                    String timesJson = freightTemplate.getCanAppointmentTime();
                    JSONArray jsonArray = JSONArray.parseArray(timesJson);
                    BigDecimal subscribePrice = BigDecimal.ZERO;
                    for (Object o : jsonArray) {
                        JSONObject object = (JSONObject) o;
                        if (object.getInteger("id").equals(subscribe.getTimeId())) {
                            subscribePrice = object.getBigDecimal("extraCharge");
                            subscribe.setStartTime(object.getString("startTime"));
                            subscribe.setEntTime(object.getString("entTime"));
                            break;
                        }
                    }
                    subscribe.setPrice(subscribePrice);
                    deliveryPrice = normalPrice.add(subscribePrice);
                    deliverChoose = JSONObject.toJSONString(subscribe);
                }
            } else if (AgedmallShipDictConstant.SHIP_SN_HOSPITAL.equals(delivery.getType())) {
                //用户选择的医院加急信息
                isHospital = litemallAddress.getIsHospital();
                hospitalId = litemallAddress.getHospitalId();
                hospitalName = litemallAddress.getHospitalName();

                //dayHourReach 今日小时达 = 子订单金额 + 普通配送费 + 加急费
                //subHourReach 预约小时达 = 子订单金额 + 普通配送费 + 预约费
                //dayStoreSelf 今日到店自提 = 子订单金额 + 自提服务费
                //subStoreSelf 预约到店自提 = 子订单金额 + 预约费
                //subHospitalSelf 预约到院自提 = 子订单金额 + 预约费

                TempSubOrderParamDeliveryHospital hospital = delivery.getHospital();
                AgedmallHospitalSend agedmallHospitalSend = agedmallHospitalSendService.getById(hospital.getHosId());
                String type = hospital.getType();
                //配送费用 自提的均为0，非自提的根据计算获取
                BigDecimal distributionFee = BigDecimal.ZERO;
                if ("subStoreSelf".equals(type) || "dayStoreSelf".equals(type)) {
                    extractShop = store.getId().intValue();
                } else if ("subHospitalSelf".equals(type)) {
                    extractShop = agedmallHospitalSend.getId();
                } else {
                    extractShop = null;
                    distributionFee = normalPrice;
                }

                //判断完自提后的配送费用
                normalPrice = distributionFee;

                //判断医院自提
                if ("subHourReach".equals(type) || "subStoreSelf".equals(type) || "subHospitalSelf".equals(type)) {
                    //预约费
                    Integer timeId = delivery.getHospital().getTimeId();
                    List<HospitalSendTimePeriodDto> sendDtoList = JSON.parseArray(agedmallHospitalSend.getTimePeriod(), HospitalSendTimePeriodDto.class);
                    HospitalSendTimePeriodDto periodDto = sendDtoList.parallelStream().filter(s -> s.getId() == timeId.intValue()).findFirst().orElse(null);
                    BigDecimal subPrice = periodDto != null ? periodDto.getCost() : BigDecimal.ZERO;
                    hospital.setStartTime(periodDto.getStartTime());
                    hospital.setEndTime(periodDto.getEndTime());
                    deliveryPrice = normalPrice.add(subPrice);
                    if("subHospitalSelf".equals(type)){
                        //如果选择到桩自提  判断自提点是否设置了免费
                        AgedmallHospitalSendSelfLocation hospitalSendSelfLocation = agedmallHospitalSendSelfLocationMapper.selectByPrimaryKey(delivery.getHospital().getPosId());
                        if(hospitalSendSelfLocation.getFreeFlag()==1){
                            deliveryPrice=BigDecimal.ZERO;
                        }
                    }
                } else if ("dayStoreSelf".equals(type)) {
                    //dayStoreSelf 今日门店自提 =（普通配送费+自提费） 自提费用是0
                    deliveryPrice = normalPrice;
                } else if ("dayHourReach".equals(type)) {
                    //dayHourReach 今日小时达（今日送货到医院）=（普通配送费+加急费）
                    hospital.setPrice(agedmallHospitalSend.getUrgentCost());
                    String today = DateUtil.today();
                    hospital.setDate(today);
                    Date startDate = DateUtil.date();
                    int hour = DateUtil.hour(startDate, true);
                    int minute = DateUtil.minute(startDate);
                    String nowStartTime = (hour < 10 ? "0" + hour : hour) + ":" + (minute < 10 ? "0" + minute : minute) + ":00";
                    //结束时间
                    DateTime endDate = DateUtil.offsetHour(startDate, 1);
                    int endHour = DateUtil.hour(endDate, true);
                    int endMinute = DateUtil.minute(endDate);
                    String nowEndTime = (endHour < 10 ? "0" + endHour : endHour) + ":" + (endMinute < 10 ? "0" + endMinute : endMinute) + ":00";
                    hospital.setStartTime(LocalTime.parse(nowStartTime));
                    hospital.setEndTime(LocalTime.parse(nowEndTime));
                    deliveryPrice = normalPrice.add(agedmallHospitalSend.getUrgentCost());
                } else {
                    deliveryPrice = normalPrice;
                }
                deliverChoose = JSONObject.toJSONString(hospital);
            }
        }
        feightFeeResult.setDeliveryChoose(deliverChoose);
        feightFeeResult.setDeliverySn(deliverySn);
        feightFeeResult.setExtractShop(extractShop);
        feightFeeResult.setHospitalId(hospitalId);
        feightFeeResult.setHospitalName(hospitalName);
        feightFeeResult.setIsHospital(isHospital);
        feightFeeResult.setDeliveryPrice(deliveryPrice);
        return feightFeeResult;
    }


    // 获取快递运费
    // pickUp 是否是取回
    public BigDecimal getCloudFeight(StoreGoodsVo goodsVo, Integer provinceId, Integer cloudStockId,boolean pickUp) {

        BigDecimal feightPrice = BigDecimal.ZERO;
        List<CloudExpressModelForm> cloudExpressModelFormList = JSONArray.parseArray(goodsVo.getCloudJson(), CloudExpressModelForm.class);
        CloudExpressModelForm cloudModel = cloudExpressModelFormList.stream().filter(express -> express.getId().equals(cloudStockId)).findFirst().get();
        if ((byte) 0 == goodsVo.getLogisticsType()) {
            if(pickUp){
                //不免运费
                if(goodsVo.getPickFreight()==0){
                    return cloudModel.getDeliveryCost();
                }
                //免运费
                else if(goodsVo.getPickFreight()==1){
                    return feightPrice;
                }
                //满足条件免运费
                else{
                    BigDecimal goodsPrice = null;
                    if (GoodsConstant.GOODS_TYPE_SALE.equals(goodsVo.getGoodsType())) {
                        goodsPrice = goodsVo.getSaleRetailPrice().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    } else {
                        goodsPrice = goodsVo.getLeaseDeposit().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    }
                    //满足条件
                    if (goodsPrice.compareTo(goodsVo.getPickFreightCondition()) >= 0) {
                        return feightPrice;
                    }
                    //不满足条件
                    else{
                        return cloudModel.getDeliveryCost();
                    }

                }

            }
            else{
                return cloudModel.getRecoveryCost();
            }

        } else {
            Long templateId=null;
            if(pickUp){
                //不免运费
                if(goodsVo.getPickFreight()==0){
                    templateId=cloudModel.getModelDeliveryId().longValue();
                }
                //免运费
                else if(goodsVo.getPickFreight()==1){
                    return feightPrice;
                }
                //满足条件免运费
                else{
                    BigDecimal goodsPrice = null;
                    if (GoodsConstant.GOODS_TYPE_SALE.equals(goodsVo.getGoodsType())) {
                        goodsPrice = goodsVo.getSaleRetailPrice().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    } else {
                        goodsPrice = goodsVo.getLeaseDeposit().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    }
                    //满足条件
                    if (goodsPrice.compareTo(goodsVo.getPickFreightCondition()) >= 0) {
                        return feightPrice;
                    }
                    //不满足条件
                    else{
                        templateId=cloudModel.getModelDeliveryId().longValue();
                    }

                }

            }
            else{
                templateId=cloudModel.getModelRecoveryId().longValue();
            }
            AgedmallFreightTemplate freightTemplate = agedmallFreightTemplateService.findById(templateId);
            List<ExpressFreightTemplate> expressFreightTemplates = JSONObject.parseArray(freightTemplate.getExpressTemplate(), ExpressFreightTemplate.class);
            ExpressFreightTemplate template = null;
            for (ExpressFreightTemplate expressFreightTemplate : expressFreightTemplates) {
                String[] regionArr = expressFreightTemplate.getRegion().split(",");
                if (ArrayUtils.contains(regionArr, provinceId + "")) {
                    template = expressFreightTemplate;
                    break;
                }
            }
            // 不支持此区域
            if (null == template) {
                return BigDecimal.valueOf(-1);
            }
            BigDecimal number = null;
            // 按件
            if (0 == freightTemplate.getPayType()) {
                number = BigDecimal.valueOf(goodsVo.getStock());
                // 按重量
            } else {
                number = goodsVo.getWeight().divide(BigDecimal.valueOf(1000));
            }

            feightPrice = template.getPiece();
            if (number.compareTo(template.getTheFirstPiece()) > 0) {
                Integer overNumber = number.subtract(template.getTheFirstPiece()).divide(template.getAhead()).setScale(0, BigDecimal.ROUND_CEILING).intValue();
                feightPrice = template.getPiece().add(template.getCharge().multiply(BigDecimal.valueOf(overNumber)));
            }
        }
        logger.debug("费用{}", feightPrice);
        return feightPrice;
    }

    // 获取同城运费 超出范围返回-1
    // 是否是取回
    public BigDecimal getFeight(StoreGoodsVo goodsVo, AgedmallStore store, BigDecimal lng, BigDecimal lat,boolean pickUp) {
        BigDecimal feightPrice = BigDecimal.ZERO;
        if ((byte) 0 == goodsVo.getLogisticsType()) {
            if(pickUp){
                //不免运费
                if(goodsVo.getPickFreight()==0){
                    return goodsVo.getPickUpCost();
                }
                //免运费
                else if(goodsVo.getPickFreight()==1){
                    return feightPrice;
                }
                //满足条件免运费
                else{
                    BigDecimal goodsPrice = null;
                    if (GoodsConstant.GOODS_TYPE_SALE.equals(goodsVo.getGoodsType())) {
                        goodsPrice = goodsVo.getSaleRetailPrice().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    } else {
                        goodsPrice = goodsVo.getLeaseDeposit().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    }
                    //满足条件
                    if (goodsPrice.compareTo(goodsVo.getPickFreightCondition()) >= 0) {
                        return feightPrice;
                    }
                    //不满足条件
                    else{
                        return goodsVo.getPickUpCost();
                    }
                }
            }
            else if (goodsVo.getSameCitySendType() == 0) {
                  return   goodsVo.getExpressCost();
            } else {
                return goodsVo.getSameCityCost();
            }
        } else {
            Long templateId = null;
            Integer sameCitySendType = goodsVo.getSameCitySendType();
            Integer pickUpInt = goodsVo.getPickUp();
            Integer express = goodsVo.getExpress();
            Integer sameCity = goodsVo.getSameCity();
            if(sameCitySendType != null&&pickUp){
                //不免运费
                if(goodsVo.getPickFreight()==0){
                    templateId=pickUpInt.longValue();
                }
                //免运费
                else if(goodsVo.getPickFreight()==1){
                    return feightPrice;
                }
                //满足条件免运费
                else{
                    BigDecimal goodsPrice = null;
                    if (GoodsConstant.GOODS_TYPE_SALE.equals(goodsVo.getGoodsType())) {
                        goodsPrice = goodsVo.getSaleRetailPrice().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    } else {
                        goodsPrice = goodsVo.getLeaseDeposit().multiply(BigDecimal.valueOf(goodsVo.getStock()));
                    }
                    //满足条件
                    if (goodsPrice.compareTo(goodsVo.getPickFreightCondition()) >= 0) {
                        return feightPrice;
                    }
                    //不满足条件
                    else{
                        templateId=pickUpInt.longValue();
                    }
                }
            }
            else if (sameCitySendType != null && sameCitySendType == 0) {
                    templateId=express.longValue();
            } else {
                templateId=sameCity.longValue();
            }
            AgedmallFreightTemplate freightTemplate =  agedmallFreightTemplateService.findById(templateId);
            if(freightTemplate == null) {
                logger.error("运费模板为空 {}", goodsVo.getId());
                return BigDecimal.ZERO;
            }
            // 实际配送距离
            GlobalCoordinates source = new GlobalCoordinates(lat.doubleValue(), lng.doubleValue());
            GlobalCoordinates target = new GlobalCoordinates(store.getLat().doubleValue(), store.getLng().doubleValue());
            GeodeticCurve geoCurve = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.Sphere, source, target);
            double distance = geoCurve.getEllipsoidalDistance();
            logger.debug("总距离{}米", distance);
//            int meter = (int)Math.ceil(distance / 1000);
            BigDecimal meter = new BigDecimal(distance / 1000);
            logger.debug("总距离{}公里", meter);
            // 按区域配送
            if (1 == freightTemplate.getPayType()) {
                // 未超出配送范围
                if (freightTemplate.getDeliveryRange().compareTo(meter) > -1) {
                    feightPrice = feightPrice.add(freightTemplate.getFixedPay());
                    logger.debug("按区域配送,配送范围{}公里，收费{}", freightTemplate.getDeliveryRange(), freightTemplate.getFixedPay());
                    // 超出配送范围
                } else {
                    return BigDecimal.valueOf(-1);
                }
                // 按距离配送
                // sunj todo 计算两点实际距离，而非直线距离
            } else {
                // 未超出配送范围
                if (freightTemplate.getDeliveryRange().compareTo(meter) > -1) {
                    if (meter.compareTo(freightTemplate.getSameCityFirstUnit()) < 1) {
                        feightPrice = feightPrice.add(freightTemplate.getSameCityFirstUnitPay());
                        logger.debug("按距离配送,配送范围{}公里，固定收费{}", freightTemplate.getSameCityFirstUnit(), freightTemplate.getSameCityFirstUnitPay());
                    } else {
                        // 超出距离倍数
                        int rate = (meter.subtract(freightTemplate.getSameCityFirstUnit())).divide(freightTemplate.getSameCityAfterUnit()).setScale(0, BigDecimal.ROUND_CEILING).intValue();
                        BigDecimal afterPrice = freightTemplate.getSameCityAfterUnitPay().multiply(BigDecimal.valueOf(rate));
                        feightPrice = feightPrice.add(freightTemplate.getSameCityFirstUnitPay()).add(afterPrice);
                        logger.debug("按距离配送,配送范围{}公里，固定收费{}，超出部分每{}公里收费{}，共收费{}", freightTemplate.getSameCityFirstUnit(),
                                freightTemplate.getSameCityFirstUnitPay(), freightTemplate.getSameCityAfterUnit(), freightTemplate.getSameCityAfterUnitPay(), afterPrice);
                    }
                    // 超出配送范围
                } else {
                    return BigDecimal.valueOf(-1);
                }
            }
            // 超重计算
            if (freightTemplate.getAdditionalPayType()==null||freightTemplate.getAdditionalPayType() == 0) {
                BigDecimal actualWeight = goodsVo.getWeight().divide(BigDecimal.valueOf(1000));
                BigDecimal tempWeight = freightTemplate.getWeight();
                BigDecimal tempAfterUnit = freightTemplate.getWeightAfterUnit();
                if (tempWeight.compareTo(BigDecimal.ZERO) > 0 && tempAfterUnit.compareTo(BigDecimal.ZERO) > 0 && actualWeight.compareTo(tempWeight) > 0) {
                    int overWeight = (actualWeight.subtract(freightTemplate.getWeight()).divide(tempAfterUnit)).setScale(0, BigDecimal.ROUND_CEILING).intValue();
                    BigDecimal overPrice = freightTemplate.getWeightAfterUnitPay().multiply(BigDecimal.valueOf(overWeight));
                    feightPrice = feightPrice.add(overPrice);
                    logger.debug("{}公斤内不收费，超出部分每{}公斤收费{}，当前{}公斤，共收费{}}", freightTemplate.getWeight(), freightTemplate.getWeightAfterUnit(),
                            freightTemplate.getWeightAfterUnitPay(), actualWeight, overPrice);
                }
            } else {
                BigDecimal number = BigDecimal.valueOf(goodsVo.getStock());
                if (freightTemplate.getWeight().compareTo(number) > 0) {
                    //超出倍数
                    int beyondSize = freightTemplate.getWeight().subtract(number).divide(freightTemplate.getWeightAfterUnit()).setScale(0, BigDecimal.ROUND_UP).intValue();
                    BigDecimal beyondPrice = freightTemplate.getWeightAfterUnitPay().multiply(BigDecimal.valueOf(beyondSize));
                    feightPrice = feightPrice.add(beyondPrice);
                    logger.debug("{}件内不收费，超出部分每{}件收费{}，当前{}件，共收费{}}", freightTemplate.getWeight(), freightTemplate.getWeightAfterUnit(),
                            freightTemplate.getWeightAfterUnitPay(), number, beyondPrice);
                }
            }
        }
        logger.debug("总费用{}", feightPrice);
        return feightPrice;
    }


    /**
     * 归还设备后订单结算,返回需要退还的费用
     *
     * @param bigOrderCode
     * @param itemOrderCode
     * @return
     */
    public LeaseRefundData calLeaseOrderSettlementRefund(String bigOrderCode, String itemOrderCode) {
        //0.获取支付的预付金金额
        LitemallOrderItem orderItem = orderService.getOrderItemByOrderCode(itemOrderCode);
        long bigOrderId = orderItem.getParentId();
        int childOrderId = orderItem.getId();

        BigDecimal totalPay = orderItem.getActualPrice();
        logger.debug("结算租赁订单预付金:{},{},{}", bigOrderCode, itemOrderCode, totalPay);

        //1.获取配送费用 是否后付费的，后付费的需要计算
        BigDecimal payDeliverFee = orderItem.getFreightPrice();
        AgedmallOrderFeeExt afterPayDeliverFee = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.AFTER_PAY_DELIVER_FEE.getExtName());
        BigDecimal afterDeliverFee = afterPayDeliverFee != null ? afterPayDeliverFee.getFee() : null;
        BigDecimal deliverFee = afterDeliverFee != null && afterDeliverFee.doubleValue() > 0 ? afterDeliverFee : (payDeliverFee == null ? BigDecimal.ZERO : payDeliverFee);
        logger.debug("结算租赁订单后付费配送费:{},{},{},{}", bigOrderCode, itemOrderCode, afterDeliverFee, payDeliverFee);

        //扣除上门服务费
        AgedmallLeaseGoodsReturnRecord agedmallLeaseGoodsReturnRecord = agedmallLeaseGoodsReturnRecordService.findByOrderIdAndSubOrderId(bigOrderId + "", childOrderId + "");
        BigDecimal updoorFee = agedmallLeaseGoodsReturnRecord != null ? agedmallLeaseGoodsReturnRecord.getUpdoorPrice() : BigDecimal.ZERO;

        //2.获取租金费用
        //获取设备门店商品id
        LitemallOrderGoods orderGoods = litemallOrderGoodsService.getOrderGoodsByChildOrderCode(itemOrderCode);
        int equStoreGoodsId = orderGoods.getStoreGoodsId();
        //使用天数 先获取签收的时间
        LocalDateTime signTime = getUserSignTime(orderGoods);
        //从签收当日凌晨进行计费
        LocalDateTime startTime = LocalDateTime.of(signTime.getYear(), signTime.getMonthValue(), signTime.getDayOfMonth(), 0, 0);
        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(now, startTime);
        long costDays = duration.toDays();
        //计算租金
        BigDecimal rent = ladderCountRent(equStoreGoodsId, costDays,orderGoods.getRuleId());
        logger.debug("结算租赁订单租金:{},{},{},{}", bigOrderCode, itemOrderCode, rent, costDays);

        //3.获取服务费用,不管有没有预约使用，只要支付成功待使用或已完成的进行计费扣除
        BigDecimal serviceFee = agedmallOnlinesService.getServiceOrderFee(bigOrderId);
        logger.debug("结算租赁订单服务费:{},{},{}", bigOrderCode, itemOrderCode, serviceFee);

        //4.获取配件费用
        BigDecimal partsFee = agedMallOrderDbService.getOrderFeeByGoodsType(bigOrderCode, itemOrderCode, OrderGoodsConstant.TYPE_CUSTOM);
        logger.debug("结算租赁订单配件费:{},{},{}", bigOrderCode, itemOrderCode, partsFee);

        //5.获取包材费用
        AgedmallOrderFeeExt sendPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal sentPackingFee = sendPackingFeeExt != null ? sendPackingFeeExt.getFee() : BigDecimal.ZERO;
        AgedmallOrderFeeExt getPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_GET_FEE.getExtName());
        BigDecimal getPackingFee = getPackingFeeExt != null ? getPackingFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单配件费:{},{},{},{}", bigOrderCode, itemOrderCode, getPackingFee, sentPackingFee);

        //6.获取清洁费用
        AgedmallOrderFeeExt cleanFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal cleanFee = cleanFeeExt != null ? cleanFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单清洁费:{},{},{}", bigOrderCode, itemOrderCode, cleanFee);

        //TODO 7.获取可用的抵扣金
        BigDecimal deductionCoin = BigDecimal.ZERO;

        //计算可以退款金额 （预付金+抵扣金）➖（租金+配送运费+上门服务费+服务费+清洁费+包材费+配件费）=应退金额
        BigDecimal totalFee = totalPay.add(deductionCoin);
        BigDecimal costFee = rent.add(deliverFee).add(updoorFee).add(serviceFee).add(cleanFee).add(sentPackingFee).add(getPackingFee).add(partsFee);
        BigDecimal refundFee = totalFee.subtract(costFee);
        logger.debug("计算租赁结算rst:{},{},{},{},{}", bigOrderCode, itemOrderCode, totalFee, costFee, refundFee);

        LeaseRefundData leaseRefundData = new LeaseRefundData();
        leaseRefundData.setRefundFee(refundFee);
        leaseRefundData.setRent(rent);
        leaseRefundData.setDeliverFee(deliverFee);
        leaseRefundData.setTotalFee(totalFee);
        leaseRefundData.setCostFee(costFee);

        return leaseRefundData;
    }


    /**
     * 买断 设备后订单结算,返回需要退还的费用
     *
     * @param bigOrderCode
     * @param itemOrderCode
     * @return
     */
    public LeaseRefundData buyOutCalLeaseOrderSettlementRefund(String bigOrderCode, String itemOrderCode, BigDecimal totalPrice) {
        //0.获取支付的预付金金额
        LitemallOrderItem orderItem = orderService.getOrderItemByOrderCode(itemOrderCode);
        long bigOrderId = orderItem.getParentId();
        int childOrderId = orderItem.getId();

        BigDecimal totalPay = orderItem.getActualPrice();
        logger.debug("结算租赁订单预付金:{},{},{}", bigOrderCode, itemOrderCode, totalPay);

        //1.获取配送费用 是否后付费的，后付费的需要计算
        BigDecimal payDeliverFee = orderItem.getFreightPrice();
        AgedmallOrderFeeExt afterPayDeliverFee = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.AFTER_PAY_DELIVER_FEE.getExtName());
        BigDecimal afterDeliverFee = afterPayDeliverFee != null ? afterPayDeliverFee.getFee() : null;
        BigDecimal deliverFee = afterDeliverFee != null && afterDeliverFee.doubleValue() > 0 ? afterDeliverFee : (payDeliverFee == null ? BigDecimal.ZERO : payDeliverFee);
        logger.debug("结算租赁订单后付费配送费:{},{},{},{}", bigOrderCode, itemOrderCode, afterDeliverFee, payDeliverFee);

        //扣除上门服务费
        AgedmallLeaseGoodsReturnRecord agedmallLeaseGoodsReturnRecord = agedmallLeaseGoodsReturnRecordService.findByOrderIdAndSubOrderId(bigOrderId + "", childOrderId + "");
        BigDecimal updoorFee = agedmallLeaseGoodsReturnRecord != null ? agedmallLeaseGoodsReturnRecord.getUpdoorPrice() : BigDecimal.ZERO;

        //2.获取租金费用
        //获取设备门店商品id
        LitemallOrderGoods orderGoods = litemallOrderGoodsService.getOrderGoodsByChildOrderCode(itemOrderCode);
        int equStoreGoodsId = orderGoods.getStoreGoodsId();
        //使用天数 先获取签收的时间
        LocalDateTime signTime = getUserSignTime(orderGoods);
        //从签收当日凌晨进行计费
        LocalDateTime startTime = LocalDateTime.of(signTime.getYear(), signTime.getMonthValue(), signTime.getDayOfMonth(), 0, 0);
        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(now, startTime);
        long costDays = duration.toDays();
        //计算租金
        BigDecimal rent = ladderCountRent(equStoreGoodsId, costDays,orderGoods.getRuleId());
        logger.debug("结算租赁订单租金:{},{},{},{}", bigOrderCode, itemOrderCode, rent, costDays);

        //3.获取服务费用,不管有没有预约使用，只要支付成功待使用或已完成的进行计费扣除
        BigDecimal serviceFee = agedmallOnlinesService.getServiceOrderFee(bigOrderId);
        logger.debug("结算租赁订单服务费:{},{},{}", bigOrderCode, itemOrderCode, serviceFee);

        //4.获取配件费用
        BigDecimal partsFee = agedMallOrderDbService.getOrderFeeByGoodsType(bigOrderCode, itemOrderCode, OrderGoodsConstant.TYPE_CUSTOM);
        logger.debug("结算租赁订单配件费:{},{},{}", bigOrderCode, itemOrderCode, partsFee);

        //5.获取包材费用
        AgedmallOrderFeeExt sendPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal sentPackingFee = sendPackingFeeExt != null ? sendPackingFeeExt.getFee() : BigDecimal.ZERO;
        AgedmallOrderFeeExt getPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_GET_FEE.getExtName());
        BigDecimal getPackingFee = getPackingFeeExt != null ? getPackingFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单配件费:{},{},{},{}", bigOrderCode, itemOrderCode, getPackingFee, sentPackingFee);

        //6.获取清洁费用
        AgedmallOrderFeeExt cleanFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal cleanFee = cleanFeeExt != null ? cleanFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单清洁费:{},{},{}", bigOrderCode, itemOrderCode, cleanFee);

        //TODO 7.获取可用的抵扣金
        BigDecimal deductionCoin = BigDecimal.ZERO;

        //计算可以退款金额 （预付金+抵扣金）➖（租金+配送运费+上门服务费+服务费+清洁费+包材费+配件费）=应退金额
        BigDecimal totalFee = totalPay.add(deductionCoin);
        BigDecimal costFee = rent.add(deliverFee).add(updoorFee).add(totalPrice);
        BigDecimal refundFee = totalFee.subtract(costFee);
        logger.debug("计算租赁结算rst:{},{},{},{},{}", bigOrderCode, itemOrderCode, totalFee, costFee, refundFee);

        LeaseRefundData leaseRefundData = new LeaseRefundData();
        leaseRefundData.setRefundFee(refundFee);
        leaseRefundData.setRent(rent);
        leaseRefundData.setDeliverFee(deliverFee);
        leaseRefundData.setTotalFee(totalFee);
        leaseRefundData.setCostFee(costFee);

        return leaseRefundData;
    }


    /**
     * 获取用户签收的时间
     *
     * @param orderGoods
     * @return
     */
    public LocalDateTime getUserSignTime(LitemallOrderGoods orderGoods) {
        String itemOrderCode = orderGoods.getChildOrderCode();
        //使用天数 先获取签收的时间
        long orderGoodsId = orderGoods.getId();
        AgedmallLgGoodsSignForRecord signForRecord = agedmallOrderLogisticService.getGoodsSignRecord(itemOrderCode, orderGoodsId);
        LocalDateTime signTime = signForRecord.getSignForTime();
        //从签收当日凌晨进行计费
        signTime.plusDays(1);
        return signTime;
    }

    /**
     * 买断设备后订单的结算
     *
     * @param bigOrderCode
     * @param itemOrderCode
     * @return
     */
    public LeaseRefundData orderSettlementAfterBuyingOutTheEquipment(String bigOrderCode, String itemOrderCode, BigDecimal buyoutAmount) {
        //0.获取支付的预付金金额
        LitemallOrderItem orderItem = orderService.getOrderItemByOrderCode(itemOrderCode);
        long bigOrderId = orderItem.getParentId();
        int childOrderId = orderItem.getId();

        BigDecimal totalPay = orderItem.getActualPrice();
        logger.debug("结算租赁订单预付金:{},{},{}", bigOrderCode, itemOrderCode, totalPay);

        //1.获取配送费用 是否后付费的，后付费的需要计算
        BigDecimal payDeliverFee = orderItem.getFreightPrice();
        AgedmallOrderFeeExt afterPayDeliverFee = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.AFTER_PAY_DELIVER_FEE.getExtName());
        BigDecimal afterDeliverFee = afterPayDeliverFee != null ? afterPayDeliverFee.getFee() : null;
        BigDecimal deliverFee = afterDeliverFee != null && afterDeliverFee.doubleValue() > 0 ? afterDeliverFee : (payDeliverFee == null ? BigDecimal.ZERO : payDeliverFee);
        logger.debug("结算租赁订单后付费配送费:{},{},{},{}", bigOrderCode, itemOrderCode, afterDeliverFee, payDeliverFee);

        //扣除上门服务费
        AgedmallLeaseGoodsReturnRecord agedmallLeaseGoodsReturnRecord = agedmallLeaseGoodsReturnRecordService.findByOrderIdAndSubOrderId(bigOrderId + "", childOrderId + "");
        BigDecimal updoorFee = agedmallLeaseGoodsReturnRecord != null ? agedmallLeaseGoodsReturnRecord.getUpdoorPrice() : BigDecimal.ZERO;

        //2.获取租金费用
        //获取设备门店商品id
        LitemallOrderGoods orderGoods = litemallOrderGoodsService.getOrderGoodsByChildOrderCode(itemOrderCode);
        int equStoreGoodsId = orderGoods.getStoreGoodsId();
        //使用天数 先获取签收的时间
        long orderGoodsId = orderGoods.getId();
        AgedmallLgGoodsSignForRecord signForRecord = agedmallOrderLogisticService.getGoodsSignRecord(itemOrderCode, orderGoodsId);
        LocalDateTime signTime = signForRecord.getSignForTime();
        //从签收当日凌晨进行计费
        signTime.plusDays(1);
        LocalDateTime startTime = LocalDateTime.of(signTime.getYear(), signTime.getMonthValue(), signTime.getDayOfMonth(), 0, 0);
        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(now, startTime);
        long costDays = duration.toDays();
        //计算租金
        BigDecimal rent = ladderCountRent(equStoreGoodsId, costDays,orderGoods.getRuleId());
        logger.debug("结算租赁订单租金:{},{},{},{}", bigOrderCode, itemOrderCode, rent, costDays);

        //3.获取服务费用,不管有没有预约使用，只要支付成功待使用或已完成的进行计费扣除
        BigDecimal serviceFee = agedmallOnlinesService.getServiceOrderFee(bigOrderId);
        logger.debug("结算租赁订单服务费:{},{},{}", bigOrderCode, itemOrderCode, serviceFee);

        //4.获取配件费用
        BigDecimal partsFee = agedMallOrderDbService.getOrderFeeByGoodsType(bigOrderCode, itemOrderCode, OrderGoodsConstant.TYPE_CUSTOM);
        logger.debug("结算租赁订单配件费:{},{},{}", bigOrderCode, itemOrderCode, partsFee);

        //5.获取包材费用
        AgedmallOrderFeeExt sendPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal sentPackingFee = sendPackingFeeExt != null ? sendPackingFeeExt.getFee() : BigDecimal.ZERO;
        AgedmallOrderFeeExt getPackingFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_GET_FEE.getExtName());
        BigDecimal getPackingFee = getPackingFeeExt != null ? getPackingFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单配件费:{},{},{},{}", bigOrderCode, itemOrderCode, getPackingFee, sentPackingFee);

        //6.获取清洁费用
        AgedmallOrderFeeExt cleanFeeExt = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.PACKING_SENT_FEE.getExtName());
        BigDecimal cleanFee = cleanFeeExt != null ? cleanFeeExt.getFee() : BigDecimal.ZERO;
        logger.debug("结算租赁订单清洁费:{},{},{}", bigOrderCode, itemOrderCode, cleanFee);

        //TODO 7.获取可用的抵扣金
        BigDecimal deductionCoin = BigDecimal.ZERO;

        //计算可以退款金额 （预付金+抵扣金）➖（配送运费+买断金额）=应退金额
        BigDecimal totalFee = totalPay.add(deductionCoin);
        BigDecimal costFee = deliverFee.add(updoorFee).add(buyoutAmount);
        BigDecimal refundFee = totalFee.subtract(costFee);
        logger.debug("计算租赁结算rst:{},{},{},{},{}", bigOrderCode, itemOrderCode, totalFee, costFee, refundFee);

        LeaseRefundData leaseRefundData = new LeaseRefundData();
        //退还金额
        leaseRefundData.setRefundFee(refundFee);
        //租金
        leaseRefundData.setRent(rent);
        //运费
        leaseRefundData.setDeliverFee(deliverFee);
        //用户的支付总价格
        leaseRefundData.setTotalFee(totalFee);

        return leaseRefundData;
    }


    /**
     * 归还设备后订单结算,返回需要退还的费用
     *
     * @param bigOrderCode
     * @param itemOrderCode
     * @return
     */
    @Transactional
    public LeaseRefundData orderSettlementCalRefund(String bigOrderCode, String itemOrderCode) {
        //0.获取支付的预付金金额
        LitemallOrderItem orderItem = orderService.getOrderItemByOrderCode(itemOrderCode);

        BigDecimal totalPay = orderItem.getActualPrice();
        logger.debug("结算租赁订单预付金:{},{},{}", bigOrderCode, itemOrderCode, totalPay);

        //1.获取配送费用 是否后付费的，后付费的需要计算
        BigDecimal payDeliverFee = orderItem.getFreightPrice();
        AgedmallOrderFeeExt afterPayDeliverFee = agedmallFreightTemplateService.getOrderExtFeeDataByName(bigOrderCode, itemOrderCode, OrderFeeExtNameEnum.AFTER_PAY_DELIVER_FEE.getExtName());
        BigDecimal afterDeliverFee = afterPayDeliverFee != null ? afterPayDeliverFee.getFee() : null;
        BigDecimal deliverFee = afterDeliverFee != null && afterDeliverFee.doubleValue() > 0 ? afterDeliverFee : (payDeliverFee == null ? BigDecimal.ZERO : payDeliverFee);
        logger.debug("结算租赁订单后付费配送费:{},{},{},{}", bigOrderCode, itemOrderCode, afterDeliverFee, payDeliverFee);


        //计算可以退款金额 （预付金+抵扣金）➖（租金+配送运费+买断金额）=应退金额
        BigDecimal totalFee = totalPay;
        BigDecimal refundFee = totalFee.subtract(deliverFee);

        LeaseRefundData leaseRefundData = new LeaseRefundData();
        //退还金额
        leaseRefundData.setRefundFee(refundFee);
        //运费
        leaseRefundData.setDeliverFee(deliverFee);
        //用户的支付总价格
        leaseRefundData.setTotalFee(totalFee);
        return leaseRefundData;

    }

    /**
     * 计算顺丰的快递费用
     *
     * @param weight 重量，单位KG
     * @param len    长，单位cm
     * @param height 高,单位cm
     * @param width  宽,单位cm
     * @return
     */
    public ShunfengFeeResult calShunfengFee(double weight, int len, int height, int width) {
        //顺丰标快
        //体积重量=长(cm)×宽(cm)×高(cm)÷12000。
        BigDecimal volume = new BigDecimal(len * width * height).divide(new BigDecimal("12000"), 4, BigDecimal.ROUND_HALF_UP);
        BigDecimal standVolFee = calShunfengBiaokuaiFee(volume);
        BigDecimal standFee = calShunfengBiaokuaiFee(new BigDecimal(weight + ""));
        BigDecimal biaoKuaiFee = standVolFee.compareTo(standFee) > 0 ? standVolFee : standFee;


        BigDecimal volumeDa = new BigDecimal(len * width * height).divide(new BigDecimal("6000"), 4, BigDecimal.ROUND_HALF_UP);
        BigDecimal standDaVolFee = calShunfengBiaozhunDaFee(volumeDa);
        BigDecimal standDaFee = calShunfengBiaozhunDaFee(new BigDecimal(weight));
        BigDecimal biaozhundaFee = standDaVolFee.compareTo(standDaFee) > 0 ? standDaVolFee : standDaFee;

        return biaoKuaiFee.compareTo(biaozhundaFee) < 0 ? new ShunfengFeeResult("2", biaoKuaiFee) : new ShunfengFeeResult("255", biaozhundaFee);
    }

    private BigDecimal calShunfengBiaozhunDaFee(BigDecimal weight) {
        BigDecimal firstFee = new BigDecimal("39");
        BigDecimal firstWeight = new BigDecimal("20");
        BigDecimal maxWeight = new BigDecimal("60");
        BigDecimal stepFee = new BigDecimal("1.9");
        BigDecimal standVolFee = null;

        if (weight.compareTo(BigDecimal.TEN) < 0) {
            weight = weight.setScale(1, BigDecimal.ROUND_HALF_DOWN);
        } else if (weight.compareTo(new BigDecimal("100")) < 0) {
            weight = weight.setScale(1, BigDecimal.ROUND_HALF_DOWN);
            BigDecimal[] modRst = weight.multiply(BigDecimal.TEN).divideAndRemainder(BigDecimal.TEN);
            if (modRst[1].compareTo(new BigDecimal("2")) <= 0) {
                weight = modRst[0];
            } else if (modRst[1].compareTo(new BigDecimal("3")) <= 0) {
                weight = modRst[0].add(new BigDecimal("0.5"));
            } else if (modRst[1].compareTo(new BigDecimal("7")) <= 0) {
                weight = modRst[0].add(new BigDecimal("0.5"));
            } else if (modRst[1].compareTo(new BigDecimal("8")) >= 0) {
                weight = modRst[0].add(BigDecimal.ONE);
            }
        } else {
            weight = weight.setScale(0, BigDecimal.ROUND_HALF_DOWN);
        }

        if (weight.compareTo(firstWeight) <= 0) {
            standVolFee = firstFee;
        } else if (weight.compareTo(maxWeight) <= 0) {
            //20~60
            standVolFee = firstFee.add(weight.subtract(firstWeight).multiply(stepFee));
        } else {
            //60以上
            firstFee = new BigDecimal("132");
            stepFee = new BigDecimal("1.5");
            standVolFee = firstFee.add(weight.subtract(maxWeight).multiply(stepFee));
        }
        return standVolFee;
    }

    private BigDecimal calShunfengBiaokuaiFee(BigDecimal weight) {
        BigDecimal firstFee = new BigDecimal("12");
        BigDecimal firstWeight = new BigDecimal("10");
        BigDecimal maxWeight = new BigDecimal("100");
        BigDecimal stepFee = new BigDecimal("2");
        BigDecimal standVolFee = BigDecimal.ZERO;
        if (weight.compareTo(firstWeight) <= 0) {
            weight = weight.setScale(1, BigDecimal.ROUND_HALF_DOWN);
            standVolFee = firstFee.add(weight.subtract(BigDecimal.ONE).multiply(stepFee));
        } else if (weight.compareTo(maxWeight) <= 0) {
            weight = weight.setScale(1, BigDecimal.ROUND_HALF_DOWN);
            BigDecimal[] modRst = weight.multiply(BigDecimal.TEN).divideAndRemainder(BigDecimal.TEN);
            if (modRst[1].compareTo(new BigDecimal("2")) <= 0) {
                weight = modRst[0];
            } else if (modRst[1].compareTo(new BigDecimal("3")) <= 0) {
                weight = modRst[0].add(new BigDecimal("0.5"));
            } else if (modRst[1].compareTo(new BigDecimal("7")) <= 0) {
                weight = modRst[0].add(new BigDecimal("0.5"));
            } else if (modRst[1].compareTo(new BigDecimal("8")) >= 0) {
                weight = modRst[0].add(BigDecimal.ONE);
            }
            standVolFee = firstFee.add(weight.subtract(BigDecimal.ONE).multiply(stepFee));
        } else {
            weight = weight.setScale(0, BigDecimal.ROUND_HALF_DOWN);
            standVolFee = firstFee.add(weight.subtract(BigDecimal.ONE).multiply(stepFee));
        }
        return standVolFee;
    }


}
